


# conv 模块垃圾桶



#! 下面重参数化卷积，与 Conv2 模块效果重复了。 不过，比 Conv2 做得更彻底，将批规范化也整合到卷积层，推理更快。

class RepConv_unused_use_Conv2(nn.Module):   # 建议用 Conv2 ，别用 RepConv
    """ 
    RepConv is a basic rep-style block, including training and deploy status.

    This module is used in RT-DETR.
    Based on https://github.com/DingXiaoH/RepVGG/blob/main/repvgg.py

RepConv（Re-parameterized Convolution，重参数化卷积）是一种在训练时采用多分支结构，而在推理时合并为单一卷积层的优化技术。
这种设计能够在不损失精度的前提下，显著提升模型的推理速度和效率。 与 Conv2 模块效果重复。
    """

    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=3, s=1, p=1, g=1, d=1, act=True, bn=False, deploy=False):
        """Initializes Light Convolution layer with inputs, outputs & optional activation function."""
        super().__init__()
        assert k == 3 and p == 1   # 确保卷积核是3*3的，而且填充固定为1.>> 
        assert d == 1  # 显然，d也要为1.否则前面定义p == 1就没意义。
        self.g = g
        self.c1 = c1
        self.c2 = c2
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

        #输入输出特征图尺寸，通道数都一样的时候，规范化层才有效。
        self.bn = nn.BatchNorm2d(num_features=c1) if bn and c2 == c1 and s == 1 else None


        self.conv1 = Conv(c1, c2, k, s, p=p, g=g, act=False)
        self.conv2 = Conv(c1, c2, 1, s, p=(p - k // 2), g=g, act=False)

    def forward_fuse(self, x):
        """Forward process."""
        return self.act(self.conv(x))

    def forward(self, x):
        """Forward process."""
        id_out = 0 if self.bn is None else self.bn(x)
        return self.act(self.conv1(x) + self.conv2(x) + id_out)

    def get_equivalent_kernel_bias(self):
        """Returns equivalent kernel and bias by adding 3x3 kernel, 1x1 kernel and identity kernel with their biases."""
        kernel3x3, bias3x3 = self._fuse_bn_tensor(self.conv1)
        kernel1x1, bias1x1 = self._fuse_bn_tensor(self.conv2)
        kernelid, biasid = self._fuse_bn_tensor(self.bn)
        return kernel3x3 + self._pad_1x1_to_3x3_tensor(kernel1x1) + kernelid, bias3x3 + bias1x1 + biasid

    @staticmethod
    def _pad_1x1_to_3x3_tensor(kernel1x1):
        """Pads a 1x1 tensor to a 3x3 tensor."""
        if kernel1x1 is None:
            return 0
        else:
            return torch.nn.functional.pad(kernel1x1, [1, 1, 1, 1])

    def _fuse_bn_tensor(self, branch):
        """Generates appropriate kernels and biases for convolution by fusing branches of the neural network."""
        if branch is None:
            return 0, 0
        if isinstance(branch, Conv):
            kernel = branch.conv.weight
            running_mean = branch.bn.running_mean
            running_var = branch.bn.running_var
            gamma = branch.bn.weight
            beta = branch.bn.bias
            eps = branch.bn.eps
        elif isinstance(branch, nn.BatchNorm2d):
            if not hasattr(self, "id_tensor"):
                input_dim = self.c1 // self.g
                kernel_value = np.zeros((self.c1, input_dim, 3, 3), dtype=np.float32)
                for i in range(self.c1):
                    kernel_value[i, i % input_dim, 1, 1] = 1
                self.id_tensor = torch.from_numpy(kernel_value).to(branch.weight.device)
            kernel = self.id_tensor
            running_mean = branch.running_mean
            running_var = branch.running_var
            gamma = branch.weight
            beta = branch.bias
            eps = branch.eps
        std = (running_var + eps).sqrt() # type: ignore
        t = (gamma / std).reshape(-1, 1, 1, 1)
        return kernel * t, beta - running_mean * gamma / std # type: ignore

    def fuse_convs(self):
        """Combines two convolution layers into a single layer and removes unused attributes from the class."""
        if hasattr(self, "conv"):
            return
        kernel, bias = self.get_equivalent_kernel_bias()
        self.conv = nn.Conv2d(
            in_channels=self.conv1.conv.in_channels,
            out_channels=self.conv1.conv.out_channels,
            kernel_size=self.conv1.conv.kernel_size,
            stride=self.conv1.conv.stride, # type: ignore
            padding=self.conv1.conv.padding,
            dilation=self.conv1.conv.dilation,
            groups=self.conv1.conv.groups,
            bias=True,
        ).requires_grad_(False)
        self.conv.weight.data = kernel
        self.conv.bias.data = bias
        for para in self.parameters():
            para.detach_()
        self.__delattr__("conv1")
        self.__delattr__("conv2")
        if hasattr(self, "nm"):
            self.__delattr__("nm")
        if hasattr(self, "bn"):
            self.__delattr__("bn")
        if hasattr(self, "id_tensor"):
            self.__delattr__("id_tensor")


#! 下面两个反卷积，我觉得非常不合理。 如果结合注意力机制， 多层大卷积，我觉得还有可行性。  
# 想要从通道中还原大的特征， 只能用大卷积模板做运算。 前面混合注意力是先通道，后空间。 
# 这里用先用空间注意力确定位置，然后通道注意力确定该位置有什么。  然后用大尺寸卷积卷积核模板，少量几层还原。 
# 比如，最终特征图相比原图尺寸减小至 1/64 。原来是 6层卷积，逐层缩小1/2， 现在还原，每层扩大4倍，3层完成。
# 每层扩大4倍，卷积核相当于是7*7， 输出层只有卷积边缘会相加。   还有图像边缘的连续性，还要进行一些残差连接。  

# 这个就是后续的研究了。 这里先不管。  
# 问题是：yolo v11 是有上采样模块的，将高层的特征信息传递给底层。  -- 这里就直接线性插值，然后通道拼接替代吧。  
#! 对了,上层特征应该包含空间位置信息，比如遮挡。 这个要在连续图像中才能学习到。这个空间信息对还原低层轮廓有很大帮助。

class ConvTranspose__wait(nn.Module):
    """Convolution transpose 2d layer.  标准的反卷积模块-- 将它看作标准卷积模块的逆运算即可，相当于从多通道的信息中还原出少通道的大特征图。
    输入>>反卷积(特征图尺寸增大，通道数减小)>>批归一化>>激活函数>>输出。
    由于卷积运算是不可逆的，因此反卷积运算只能恢复特征图的尺寸，而不能恢复数值。
    
    不过，由于卷积核按图索骥的本质，从小的特征图中还原大的特征图，概率空间上还是有一定可行性的(但不大...)。
    """

    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=2, s=2, p=0, bn=True, act=True):
        """Initialize ConvTranspose2d layer with batch normalization and activation function."""
        super().__init__()
        self.conv_transpose = nn.ConvTranspose2d(c1, c2, k, s, p, bias=not bn)
        """ 
ConvTranspose2d 参数说明：
in_channels(int) – 输入信号的通道数
out_channels(int) – 卷积产生的通道数
kerner_size(int or tuple) - 卷积核的大小
stride(int or tuple,optional) - 卷积步长
padding(int or tuple, optional) - 输入的每一条边补充0的层数
output_padding(int or tuple, optional) - 输出的每一条边补充0的层数
dilation(int or tuple, optional) – 卷积核元素之间的间距
groups(int, optional) – 从输入通道到输出通道的阻塞连接数
bias(bool, optional) - 如果bias=True，添加偏置。  如果定义了批归一化，就不需要偏置了。
        """

        self.bn = nn.BatchNorm2d(c2) if bn else nn.Identity()
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        """Applies transposed convolutions, batch normalization and activation to input."""
        return self.act(self.bn(self.conv_transpose(x)))

    def forward_fuse(self, x):
        """Applies activation and convolution transpose operation to input."""
        return self.act(self.conv_transpose(x))


class DWConvTranspose2d_wait(nn.ConvTranspose2d):
    """Depth-wise transpose convolution."""

    def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0):  # ch_in, ch_out, kernel, stride, padding, padding_out
        """Initialize DWConvTranspose2d class with given parameters."""
        super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2))

























